/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2012/12/16
* File: EnnRenderSystem.h
* Blog: http://www.cnblogs.com/zengqh/
**/

#ifndef EnnRenderSystem_h__
#define EnnRenderSystem_h__

#include "EnnPrerequisites.h"

namespace Enn
{
	enum RenderMode
	{
		RENDER_FORWARD = 0,
		RENDER_PREPASS,
		RENDER_DEFERRED
	};

	/// Primitive type.
	enum PrimitiveType
	{
		TRIANGLE_LIST = 0,
		LINE_LIST
	};

	/// %Geometry type.
	enum GeometryType
	{
		GEOM_STATIC = 0,
		GEOM_SKINNED = 1,
		GEOM_INSTANCED = 2,
		GEOM_BILLBOARD = 3,
		GEOM_STATIC_NOINSTANCING = 4,
		MAX_GEOMETRYTYPES = 4,
	};

	/// Blending mode.
	enum BlendMode
	{
		BLEND_REPLACE = 0,
		BLEND_ADD,
		BLEND_MULTIPLY,
		BLEND_ALPHA,
		BLEND_ADDALPHA,
		BLEND_PREMULALPHA,
		BLEND_INVDESTALPHA,
		MAX_BLENDMODES
	};

	/// Depth or stencil compare mode.
	enum CompareMode
	{
		CMP_ALWAYS = 0,
		CMP_EQUAL,
		CMP_NOTEQUAL,
		CMP_LESS,
		CMP_LESSEQUAL,
		CMP_GREATER,
		CMP_GREATEREQUAL,
		MAX_COMPAREMODES
	};

	/// Culling mode.
	enum CullMode
	{
		CULL_NONE = 0,
		CULL_CCW,
		CULL_CW,
		MAX_CULLMODES
	};

	/// Fill mode.
	enum FillMode
	{
		FILL_SOLID = 0,
		FILL_WIREFRAME,
		FILL_POINT
	};

	/// Stencil operation.
	enum StencilOp
	{
		OP_KEEP = 0,
		OP_ZERO,
		OP_REF,
		OP_INCR,
		OP_DECR
	};

	/// Vertex/index buffer lock state.
	enum LockState
	{
		LOCK_NONE = 0,
		LOCK_HARDWARE,
		LOCK_SHADOW,
		LOCK_SCRATCH
	};

	/// Vertex elements.
	enum VertexElement
	{
		ELEMENT_POSITION = 0,
		ELEMENT_NORMAL,
		ELEMENT_COLOR,
		ELEMENT_TEXCOORD1,
		ELEMENT_TEXCOORD2,
		ELEMENT_CUBETEXCOORD1,
		ELEMENT_CUBETEXCOORD2,
		ELEMENT_TANGENT,
		ELEMENT_BLENDWEIGHTS,
		ELEMENT_BLENDINDICES,
		ELEMENT_INSTANCEMATRIX1,
		ELEMENT_INSTANCEMATRIX2,
		ELEMENT_INSTANCEMATRIX3,
		MAX_VERTEX_ELEMENTS
	};

	/// Texture filtering mode.
	enum TextureFilterMode
	{
		FILTER_NEAREST = 0,
		FILTER_BILINEAR,
		FILTER_TRILINEAR,
		FILTER_ANISOTROPIC,
		FILTER_DEFAULT,
		MAX_FILTERMODES
	};

	/// Texture addressing mode.
	enum TextureAddressMode
	{
		ADDRESS_WRAP = 0,
		ADDRESS_MIRROR,
		ADDRESS_CLAMP,
		ADDRESS_BORDER,
		MAX_ADDRESSMODES
	};

	/// Texture coordinates.
	enum TextureCoordinate
	{
		COORD_U = 0,
		COORD_V,
		COORD_W,
		MAX_COORDS
	};

	/// Texture usage types.
	enum TextureUsage
	{
		TEXTURE_STATIC = 0,
		TEXTURE_DYNAMIC,
		TEXTURE_RENDERTARGET,
		TEXTURE_DEPTHSTENCIL
	};

	/// Rendering passes.
	enum PassType
	{
		PASS_BASE = 0,
		PASS_LITBASE,
		PASS_LIGHT,
		PASS_PREALPHA,
		PASS_POSTALPHA,
		PASS_PREPASS,
		PASS_MATERIAL,
		PASS_DEFERRED,
		PASS_SHADOW,
		MAX_PASSES
	};

	/// Cube map faces.
	enum CubeMapFace
	{
		FACE_POSITIVE_X = 0,
		FACE_NEGATIVE_X,
		FACE_POSITIVE_Y,
		FACE_NEGATIVE_Y,
		FACE_POSITIVE_Z,
		FACE_NEGATIVE_Z,
		MAX_CUBEMAP_FACES
	};

	/// Shader types.
	enum ShaderType
	{
		VS = 0,
		PS,
	};

	/// Texture units.
	enum TextureUnit
	{
		TU_DIFFUSE = 0,
		TU_ALBEDOBUFFER = 0,
		TU_NORMAL = 1,
		TU_NORMALBUFFER = 1,
		TU_SPECULAR = 2,
		TU_DEPTHBUFFER = 2,
		TU_EMISSIVE = 3,
		TU_ENVIRONMENT = 4,
		MAX_MATERIAL_TEXTURE_UNITS = 5,
		TU_LIGHTRAMP = 5,
		TU_LIGHTBUFFER = 5,
		TU_LIGHTSHAPE = 6,
		TU_SHADOWMAP = 7,
		TU_FACESELECT = 8,
		TU_INDIRECTION = 9,
		MAX_TEXTURE_UNITS = 10
	};

	/// Shader parameter groups for determining need to update.
	enum ShaderParameterGroup
	{
		SP_FRAME = 0,
		SP_CAMERA,
		SP_VIEWPORT,
		SP_ZONE,
		SP_LIGHT,
		SP_VERTEXLIGHTS,
		SP_MATERIAL,
		SP_OBJECTTRANSFORM,
		SP_OBJECTDATA,
		MAX_SHADER_PARAMETER_GROUPS
	};

	class Image;
	class IndexBuffer;
	class Matrix3;
	class Matrix4;
	class Matrix3x4;
	class GPUObject;
	class GraphicsImpl;
	class RenderSurface;
	class ShaderVariation;
	class Texture;
	class Texture2D;
	class TextureCube;
	class Vector3;
	class Vector4;
	class VertexBuffer;
	class VertexDeclaration;

	struct ShaderParameter;

	class _EnnExport RenderSystem : public RenderSysAlloc
	{
	public:
		RenderSystem();
		virtual ~RenderSystem();

		bool takeScreenShot(Image& destImage);
		
		/// Begin frame rendering. Return true if device available and can render.
		bool beginFrame();

		/// End frame rendering and swap buffers.
		void EndFrame();

		/// Clear any or all of render target, depth buffer and stencil buffer.
		void Clear(
			unsigned flags, 
			const Color& color = Color(0.0f, 0.0f, 0.0f, 0.0f), 
			float depth = 1.0f, unsigned stencil = 0);

		/// Draw non-indexed geometry.
		void render(PrimitiveType type, unsigned vertexStart, unsigned vertexCount);

		/// Draw indexed geometry.
		void render(
			PrimitiveType type, 
			unsigned indexStart, 
			unsigned indexCount, 
			unsigned minVertex, 
			unsigned vertexCount);

		/// Draw indexed, instanced geometry. An instancing vertex buffer must be set.
		void renderInstanced(
			PrimitiveType type, 
			unsigned indexStart, 
			unsigned indexCount, 
			unsigned minVertex, 
			unsigned vertexCount, 
			unsigned instanceCount);

		/// Set vertex buffer.
		void SetVertexBuffer(VertexBuffer* buffer);

		/// Set multiple vertex buffers.
		bool SetVertexBuffers(
			const vector<VertexBuffer*>::type& buffers, 
			const vector<unsigned>::type& elementMasks, 
			unsigned instanceOffset = 0);
		
		/// Set index buffer.
		void SetIndexBuffer(IndexBuffer* buffer);

		/// Set shaders.
		void SetShaders(ShaderVariation* vs, ShaderVariation* ps);

		/// Set texture.
		void SetTexture(unsigned index, Texture* texture);

		/// Set default texture filtering mode.
		void SetDefaultTextureFilterMode(TextureFilterMode mode);

		/// Set render target.
		void SetRenderTarget(unsigned index, RenderSurface* renderTarget);

		/// Set render target.
		void SetRenderTarget(unsigned index, Texture2D* texture);

		/// Set depth-stencil surface.
		void SetDepthStencil(RenderSurface* depthStencil);

		/// Set depth-stencil surface.
		void SetDepthStencil(Texture2D* texture);

		/// Set view port.
		void SetViewport(const Rect& rect);

		/// Set blending mode.
		void SetBlendMode(BlendMode mode);

		/// Set color write on/off.
		void SetColorWrite(bool enable);

		/// Set hardware culling mode.
		void SetCullMode(CullMode mode);

		/// Set depth bias.
		void SetDepthBias(Real constantBias, Real slopeScaledBias);

		/// Set depth compare.
		void SetDepthTest(CompareMode mode);

		/// Set depth write on/off.
		void SetDepthWrite(bool enable);

		/// Set polygon fill mode.
		void SetFillMode(FillMode mode);

		/// Set scissor test.
		void SetScissorTest(bool enable, const Rect& rect);

		/// Set stencil test.
		void SetStencilTest(bool enable, CompareMode mode = CMP_ALWAYS, StencilOp pass = OP_KEEP, StencilOp fail = OP_KEEP, StencilOp zFail = OP_KEEP, unsigned stencilRef = 0, unsigned compareMask = M_MAX_UNSIGNED, unsigned writeMask = M_MAX_UNSIGNED);
	};
}
#endif    /* EnnRenderSystem_h__ */